/*
 *  $Id: Jog.cs 1233 2010-12-18 17:54:48Z thenn.erannor $
 *  This file is a part of Ragima CCG.
 *  (C) 2008-2010 Ragima development group.
 *
 *  Licensed under the terms of the GNU GPL License version 2.
 *
 */

using System.Collections.Generic;

using AgateLib.DisplayLib;
using AgateLib.InputLib;
using AgateLib.Geometry;

using Nereal.Serialization;

namespace Ragima {
    /// <summary>
    /// Интерфейс, предоставляющий данные о выбираемом jog'ом значении.
    /// </summary>
    public interface IJogValueProvider {
        int GetDefaultValue();
        int GetMinValue();
        int GetMaxValue();
    }

    /// <summary>
    /// Делегат получения провайдера.
    /// </summary>
    /// <param name="player">Игрок, для которого нужно получить провайдер.</param>
    /// <returns>Провайдер.</returns>
    public delegate IJogValueProvider JogValueProviderGetter(Player player);

    /// <summary>
    /// Тип цели: отсутствие конкретной цели, простое использование карты (с выводом jog-меню).
    /// </summary>
    public class JogTarget : TargetType {
        /// <summary>
        /// Цель: простое использование.
        /// </summary>
        public static readonly JogTarget Use = new JogTarget(new Languages.Phrase("target.jog.use"), false);
        /// <summary>
        /// Цель: призыв местности или существа без выбора места.
        /// </summary>
        public static readonly JogTarget Summon = new JogTarget(new Languages.Phrase("target.jog.summon"), true);

        private JogValueProviderGetter _getter;
        private JogRegion _region;

        public JogTarget(Languages.Phrase notice, JogValueProviderGetter getter) : base(notice) {
            _getter = getter;
            _region = new JogRegion(false);
        }
        private JogTarget(Languages.Phrase notice, bool summon) : base(notice) {
            _getter = null;
            _region = new JogRegion(summon);
        }

        public override void Initialize(TargetRequest request) {
            base.Initialize(request);
            IJogValueProvider provider = null;
            if (_getter != null)
                provider = _getter(Request.Player);
            if (request.Region != null)
                _region.SetData(provider, request.Region.Rect.Location);
        }

        public override int GetCount(AbstractObject caster) {
            return 1;
        }

        public override IEnumerable<Region> GetRegions() {
            yield return _region;
        }

        public override TargetArgs GetArgs(Region region) {
            var jog = region as JogRegion;
            return jog != null ? new JogTargetArgs(Request.Player, Request.Caster, jog.Value) : null;
        }

        private class JogRegion : Region {
            public const int JogSize = 88;
            public const int JogHalfSize = JogSize / 2;
            public const int JogXOffset = (Constants.SmallCardWidth - JogSize) / 2;
            public const int JogYOffset = (Constants.SmallCardHeight - JogSize) / 2;
            public static readonly Rectangle DefaultRect = new Rectangle(0, 0, JogSize, JogSize);

            public static readonly Size BigButtonSize = new Size(JogSize, JogHalfSize);
            public static readonly Size SmallButtonSize = new Size(JogHalfSize, JogHalfSize);

            public static readonly Rectangle[] Summon = { new Rectangle(new Point(0, 0), BigButtonSize), new Rectangle(new Point(JogSize * 2, 0), BigButtonSize) };
            public static readonly Rectangle[] Use = { new Rectangle(new Point(JogSize, 0), BigButtonSize), new Rectangle(new Point(JogSize * 3, 0), BigButtonSize) };
            public static readonly Rectangle[] SpinLeft = { new Rectangle(new Point(0, JogHalfSize), SmallButtonSize), new Rectangle(new Point(JogSize, JogHalfSize), SmallButtonSize), new Rectangle(new Point(JogSize * 2, JogHalfSize), SmallButtonSize), new Rectangle(new Point(JogSize * 3, JogHalfSize), SmallButtonSize) };
            public static readonly Rectangle[] SpinRight = { new Rectangle(new Point(JogHalfSize, JogHalfSize), SmallButtonSize), new Rectangle(new Point(JogSize + JogHalfSize, JogHalfSize), SmallButtonSize), new Rectangle(new Point(JogSize * 2 + JogHalfSize, JogHalfSize), SmallButtonSize), new Rectangle(new Point(JogSize * 3 + JogHalfSize, JogHalfSize), SmallButtonSize) };

            private IJogValueProvider _provider;
            private bool _summon, _down, _visible;
            private Rectangle[] _buttons;
            private int _value, _valueX, _valueY;

            private bool HasValue {
                get { return _provider != null; }
            }
            private Rectangle[] MainButton {
                get { return _summon ? Summon : Use; }
            }

            public int Value {
                get { return _value; }
            }

            public JogRegion(bool summon) : base(DefaultRect) {
                _provider = null;
                _summon = summon;
                _down = false;
                _visible = true;
                _buttons = new Rectangle[5];
            }

            public void SetData(IJogValueProvider provider, Point point) {
                _provider = provider;
                _value = HasValue ? _provider.GetDefaultValue() : 0;
                var rect = new Rectangle(point.X + JogXOffset, point.Y + JogYOffset, JogSize, JogSize);
                Rect = rect;
                _buttons[0] = rect;
                _buttons[1] = new Rectangle(rect.Location, BigButtonSize);
                _buttons[2] = new Rectangle(new Point(rect.X, rect.Y + JogHalfSize), SmallButtonSize);
                _buttons[3] = new Rectangle(new Point(rect.X + JogHalfSize, rect.Y + JogHalfSize), SmallButtonSize);
                _buttons[4] = new Rectangle(rect.X + JogHalfSize - 11, rect.Y + JogHalfSize - 12, 22, 24);
                _valueX = rect.X + JogHalfSize;
                _valueY = rect.Y + JogHalfSize - 8;
                _visible = true;
            }

            public override void Draw() {
                if (_visible) {
                    if (HasValue)
                        Display.FillRect(_buttons[4], Color.White);
                    byte focus = GetFocusButton();
                    int mainState = focus == 1 ? 1 : 0;
                    int leftState = HasValue ? (focus == 2 ? (_down ? 3 : 2) : 1) : 0;
                    int rightState = HasValue ? (focus == 3 ? (_down ? 3 : 2) : 1) : 0;
                    Data.Jog.Draw(MainButton[mainState], _buttons[1]);
                    Data.Jog.Draw(SpinLeft[leftState], _buttons[2]);
                    Data.Jog.Draw(SpinRight[rightState], _buttons[3]);
                    if (HasValue) {
                        Data.Fonts.Main.Color = Color.Black;
                        Data.Fonts.Main.DrawCenter(_valueX, _valueY, _value.ToString());
                    }
                }
            }

            public byte GetFocusButton() {
                if (!Focus)
                    return 0;
                var point = Mouse.Position;
                for (byte b = 1; b < 4; b++)
                    if (_buttons[b].Contains(point))
                        return b;
                return 0;
            }

            public override void OnClick() {
                _down = true;
                byte focus = GetFocusButton();
                switch (focus) {
                    case 1:
                        if (HasValue && (_value < _provider.GetMinValue() || _value > _provider.GetMaxValue()))
                            return;
                        _visible = false;
                        Game.Current.Target.ClickRegion(this);
                        break;
                    case 2:
                        if (HasValue && _value > _provider.GetMinValue())
                            _value--;
                        break;
                    case 3:
                        if (HasValue && _value < _provider.GetMaxValue())
                            _value++;
                        break;
                }
            }

            public override void OnClickUp() {
                _down = false;
            }

            public override void OnMouseLeave() {
                base.OnMouseLeave();
                _down = false;
            }

        }
    }

    [TypeId("jog")]
    public class JogTargetArgs : TargetArgs<int> {
        [Serialize, XmlName("value")]
        private int _value;

        public JogTargetArgs() {
        }
        public JogTargetArgs(Player player, AbstractObject caster, int value) : base(player, caster) {
            _value = value;
        }

        public override int Target {
            get { return _value; }
        }
    }
}
